package com.property.manage.service.fee;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.guardchina.framework.mybatis.model.CustomPage;
import com.guardchina.framework.util.exception.BusinessException;
import com.property.manage.dao.fee.PropertyMapper;
import com.property.manage.model.fee.Collection;
import com.property.manage.model.fee.Property;
import com.property.manage.model.fee.PropertyVo;
import com.property.manage.model.flowingWater.PropertyDeductionEntity;
import com.property.manage.model.resource.Building;
import com.property.manage.model.system.User;
import com.property.manage.model.village.Village;
import com.property.manage.service.flowingWater.ArrearsDetailService;
import com.property.manage.service.flowingWater.FlowingWaterService;
import com.property.manage.service.flowingWater.PropertyDeductionService;
import com.property.manage.service.resource.BuildingService;
import com.property.manage.service.system.UserService;
import com.property.manage.service.village.VillageService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
import java.util.List;
import java.util.Optional;

/**
 * 描述
 *
 * @author lwb
 * @since 2020/7/16
 */
@Component
@AllArgsConstructor
@Slf4j
public class PropertyService {

    private PropertyMapper propertyMapper;

    private CollectionService collectionService;

    private PropertyDeductionService propertyDeductionService;
    private UserService userService;
    private BuildingService buildingService;
    private VillageService villageService;
    @Lazy
    private FlowingWaterService flowingWaterService;
    private ArrearsDetailService arrearsDetailService;


    @Transactional(rollbackFor = Exception.class)
    public void add(Integer buildingId, Integer gradeId, LocalDate nexPayDate, String name, String mobile, BigDecimal shouldPay){

        checkIsExistBuilding(buildingId);

        Property property = new Property();
        property.setBuildingId(buildingId);
        property.setGradeId(gradeId);
        property.setNextPayDate(nexPayDate);
        property.setName(name);
        property.setMobile(mobile);
       property.setShouldPay(shouldPay);
        propertyMapper.insert(property);

        collectionService.saveOrUpdate(Collection.TYPE_PROPERTY, property.getId(), nexPayDate);
    }

    @Transactional(rollbackFor = Exception.class)
    public void update(Integer id, Integer buildingId, Integer gradeId, LocalDate nexPayDate, String name, String mobile,BigDecimal shouldPay){

        Property property = getById(id);
        if(!property.getBuildingId().equals(buildingId)){
            checkIsExistBuilding(buildingId);
        }

        property.setBuildingId(buildingId);
        property.setGradeId(gradeId);
        property.setNextPayDate(nexPayDate);
        property.setName(name);
        property.setMobile(mobile);
        property.setShouldPay(shouldPay);

        propertyMapper.updateById(property);

        collectionService.saveOrUpdate(Collection.TYPE_PROPERTY, property.getId(), nexPayDate);
    }
    public void update(Integer id,LocalDate nexPayDate){
        UpdateWrapper<Property> property=new UpdateWrapper<>();
        property.set("next_pay_date",nexPayDate);
        property.eq("id",id);
        propertyMapper.update(null,property);
        collectionService.saveOrUpdate(Collection.TYPE_PROPERTY, id, nexPayDate);
    }
    public CustomPage<PropertyVo> propertyPage(Long pageNo, Long pageSize, Integer villageId, String name){
        Page<PropertyVo> page = new Page<>(pageNo, pageSize);
        IPage<PropertyVo> result = propertyMapper.propertyPage(page, villageId, name);

        return new CustomPage<>(result);
    }

    @Transactional(rollbackFor = Exception.class)
    public void delete(Integer id) {

        propertyMapper.deleteById(id);

        collectionService.delete(Collection.TYPE_PROPERTY, id);
    }


    private void checkIsExistBuilding(Integer buildingId){
        Property property = findByBuildingId(buildingId);
        if(property != null){
            throw new BusinessException("该楼栋已添加物业管理费信息", String.format("buildingId[%s]", buildingId));
        }
    }

    private Property findByBuildingId(Integer buildingId){
        QueryWrapper<Property> wrapper = new QueryWrapper<>();
        wrapper.eq("building_id", buildingId);
        return propertyMapper.selectOne(wrapper);
    }

    public Property getById(Integer id){
        Property property = propertyMapper.selectById(id);

        return Optional.ofNullable(property).orElseThrow(() -> new BusinessException("物业管理费信息不存在", String.format("id[%s]", id)));
    }

    @Transactional(rollbackFor = Exception.class)
    public synchronized void propertyDeduction(Integer userId, Integer villageId, Integer year, Integer month){
        log.info("userId[{}], villageId[{}], year[{}], month[{}]物业费划扣", userId, villageId, year, month);
        Optional<PropertyDeductionEntity> optional = propertyDeductionService.find(villageId, year, month);
        optional.ifPresent(entity -> { throw new BusinessException(month + "月份已划扣，请勿重复划扣");});

        User user = userService.getUser(userId);
        Village village = villageService.getVillage(villageId);
        List<Building> buildings = buildingService.getBuildings(villageId);

        propertyDeductionService.add(villageId, year, month);


        LocalDate startDate = LocalDate.of(year, month, 1);
        LocalDate endDate = startDate.with(TemporalAdjusters.lastDayOfMonth());

        for (Building building : buildings) {
            BigDecimal shouldPay = village.getPropertyMoney().multiply(building.getSquare()).setScale(2, RoundingMode.HALF_UP);
            BigDecimal realFee = shouldPay.multiply(new BigDecimal(building.getDiscount())).setScale(2, RoundingMode.HALF_UP);
            try {
                flowingWaterService.propertyDeduction(user, village, building, year, month, shouldPay, realFee);
            }catch (BusinessException e){
                log.error("物业费划扣失败：buildingId[{}], year[{}], month[{}]", building.getId(), year, month);
                log.error("错误信息：", e);
                arrearsDetailService.add(building.getId(), "物业管理费", shouldPay, shouldPay.subtract(realFee), realFee, startDate, endDate, e.getShortMessage());
            }catch (Exception e){
                log.error("物业费划扣失败：buildingId[{}], year[{}], month[{}]", building.getId(), year, month);
                log.error("错误信息：", e);
                arrearsDetailService.add(building.getId(), "物业管理费", shouldPay, shouldPay.subtract(realFee), realFee, startDate, endDate, "划扣失败");
            }
        }

        propertyDeductionService.complete(villageId, year, month);

        log.info("物业费划扣完成");

    }
}
